The present invention relates in general to the field of computers and similar technologies, and in particular to software utilized in this field. More particularly, the present invention relates to exception throwers.
Computer systems process code that has been written and tested by software engineers using available testing and debugging tools. Such testing includes secondary field beta testing by volunteer users, which results in error/deficiency spotting, which results in the issuing upgraded/revised versions months and years later. Before sending the software out for field testing, the software engineers use laboratory tools, such as Java's Integrated Development Environment (IDE), to identify code that produces errors, both fatal and non-fatal.
An interface is made up of functions with inputs and outputs. For outputs, there are generally two forms: output and errors. In the Java® language, for example, there are return values (outputs) and exceptions (errors). When testing interfaces, tools such as IDE provide sophisticated support for debugging code. IDE includes a Java® programming editor that aids in the debugging process. This is accomplished by recognizing errors that occur while code is being compiling, and then highlighting the errors with distinctive colors. While IDE can recognize and can even suggest corrections to written code, IDE cannot describe what long-range effects the error has or can cause. That is, while IDE supports error trapping, error trapping is usually used to fix an existing bug. However, IDE does not provide tools or debugging aids for testing error handling code.
To test error handling code, developers have had to force error scenarios by writing specialized unit tests, changing code during testing, or taking unnatural process steps.
If a developer is comfortable using tools to test code, writing specialized unit tests may push the developer away from the testing tools of an IDE. Furthermore, many tests assume that error conditions are caused by bad input, which is not always the case. Unanticipated errors can happen from the conditions around the target component. Thus writing specialized unit tests that force bad input does not cover every testing scenario.
Changing code during testing is a dangerous practice. A software developer may choose to change a piece temporality (timing) to force an exception, such as adding a throw clause to a piece of code. However, if the developer forgets to remove this test code, then a permanent error condition is introduced.
Taking unnatural process steps is also problematic. For example, killing a particular process just to test an error handler may not be feasible if the error handling code in the same process as the code that generated the error. It is also difficult to properly determine when a process should be killed in many scenarios.
Error handling code that does not behave correctly can cause unwanted consequences in a system. For example, consider a transactional system that requires a rollback in case of a particular application exception. The error handler may not rollback properly, thus causing the system to have inconsistent data. Other unhandled exceptions may cause systems to freeze or even to crash.
For example, consider the scenario shown in FIG. 1. Calling component 102 is a software component (e.g., object) that calls a particular function or service. Target component 104 is software that services the request (\call operation\) from calling component 102. If target component 104 experiences an error when trying to service the request, then an error message (\throw ErrorException\) is returned to calling component 102. Calling component 102 then calls exception handler 106, which executes logic in response to the error. As noted above, traditional systems such as IDE's do not support testing of the code that is implemented by exception handler 106.
Object Oriented Programming (OOP), in which a system is viewed as a set of collaborating objects having methods (actions) and attributes (data), as well as procedural programming (in which calls are made to reusable subroutines), both focus on the separation and encapsulation of concerns (areas of interest) into single entities, by defining classes, methods, object factories, interfaces, etc. However, they do a poor job of addressing cross-cutting issues, such as step tracing, event logging, etc. That is, OOP and traditional linear programs have difficulty in handling code that runs across multiple software blocks caused by shared requirements among objects.
The problems described above also occur when using the programming paradigm known as Aspect-Oriented Programming (AOP). AOP focuses on a modularization and encapsulation of cross-cutting concerns. AOP addresses the issue of cross-cutting through the use of an aspect. An aspect packages advice (code that is applied to objects) and join points (points in the model where advice will be applied) into functional units in a manner that is analogous to the way OOP uses classes to package methods and attributes into objects. Join points may be at a method execution, an instantiation of an object, or a throwing of an exception.
An aspect can alter the behavior of base code (the non-aspect part of a program) by applying advice (additional behavior) to multiple join points (elements of the programming language semantics which the aspects coordinate with). This results in a logical description of a set of join points, called a pointcut. A pointcut can either match a join point or not at runtime, and may expose runtime information to a piece of advice.
Thus, an aspect is a stand-alone module that addresses operations that are scattered across (applied to) multiple program modules and tangled with (interdependent with) other modules. An aspect is made up of one or more advice (code snippets similar to methods) and a list of join points (points into a main program into which the advice should be weaved).
Weaving is the injecting of the advice presented in an aspect into the specified join points associated with each advice. That is, weaving coordinates aspects and non-aspects to ensure that advice executes at the appropriate dynamic join points.
Thus, whether a programmer is using AOP, OOP, or even linear programming, there is not a safe and efficient way to test error handling code.